using DG.Tweening;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;
using Object = System.Object;
using AppTableUtils;
using System.Data;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Logical;
using UnityEngine.Serialization;
using TMPro;


public class DialogManager : MonoBehaviour
{
    private bool dbg = false;

    [Header("选项动态尺寸")] public bool use_dynamic_choice_type = true;

    Transform _dialog_canvas_trans;

    public Transform dialog_canvas_trans
    {
        get
        {
            if (_dialog_canvas_trans == null)
            {
                _dialog_canvas_trans = BdTools.get_game_object_by_path("/DialogCanvas").transform;
                BdUtils.assert(_dialog_canvas_trans, "`dialog_canvas_trans`为空?");
            }
            return _dialog_canvas_trans;
        }
    }

    public Dictionary<string, Vector2> screen_positions = new Dictionary<string, Vector2>
    {
        {
            "left", BdTools.get_position_by_screen_scale(0.2f, 0.5f)
        },
        {
            "right", BdTools.get_position_by_screen_scale(0.8f, 0.5f)
        }
    };

    [FormerlySerializedAs("dialog_csv")] public DataTable dialog_dt;

    public GameObject dialog_canvas_obj
    {
        get
        {
            return dialog_canvas_trans.gameObject;
        }
    }

    public static DialogManager instance;

    public delegate void EventListener(String msg);

    private Dictionary<string, EventListener> eventListeners = new Dictionary<string, EventListener>();

    int current_dialog_id = 1;
    private int next_dialog_id = 1;
    DataRow current_row;
    string _file_name = null;
    private bool stop_next = false;
    private bool is_show_content = false;

    private void Awake()
    {
        if (dbg)
            BdUtils.log(" --- on DialogManager.Awake!");
        if (instance != null)
            Destroy(this);
        instance = this;
    }

    public void load_csv(string file_name = null)
    {
        if (BdUtils.is_null(file_name))
        {
            if (BdUtils.is_null(_file_name))
            {
                // _file_name = BdUtils.join(BdUtils.data_table_dir_path, "dialogs", "test_dialog.csv");
                // _file_name = BdUtils.join(BdUtils.data_table_dir_path, "dialogs", "dialog_tree.csv");
                _file_name = BdUtils.join(BdUtils.data_table_dir_path, "dialogs", "dialog_tree_1.xlsx");
            }
            file_name = _file_name;
        }
        else
        {
            file_name = BdUtils.join(BdUtils.data_table_dir_path, "dialogs", file_name);
        }
        
        dialog_dt = TableUtils.read_table(file_name, primary_key: "ID");
        
        TableUtils.show_data_table(dialog_dt);
        // BdUtils.log("~~~ TableName:", dialog_dt.TableName);
        // BdUtils.log("~~~ data_table_dir_path:", BdUtils.data_table_dir_path);
        // BdUtils.log("~~~ file_name:", file_name);
    }

    void Start()
    {
        // dialog_canvas_trans = ObjectPoolManager.instance.transform.Find("/DialogCanvas");
        choices_fixed_obj = BdTools.get_game_object_by_path("choices_fixed", dialog_canvas_obj);
        choices_dynamic_obj = BdTools.get_game_object_by_path("choices_dynamic", dialog_canvas_obj);
        BdUtils.assert(choices_fixed_obj, $"`choices_fixed_obj`为空?");
        BdUtils.assert(choices_dynamic_obj, "`choices_dynamic_obj`为空?");

        load_csv();

        // BdUtils.log("find dialog_canvas! obj_path:", BdTools.get_abs_path_by_obj(dialog_canvas_trans.gameObject));

        init_state();
    }

    // Update is called once per frame
    private float delta_time__update_dialog;

    void Update()
    {
        delta_time__update_dialog += Time.deltaTime;

        if (Input.GetKeyDown(KeyCode.E))
        {
            change_dialog_canvas_active_state();
        }
        
        if (Input.GetKeyDown(KeyCode.Space) || Input.GetMouseButtonDown(0))
        {
            if (stop_next)
                return;
            
            if (next_dialog_id == 1 || delta_time__update_dialog >= 1f)
            {
                // BdUtils.log("~~~ next dialog!");                
                next_dialog();
                delta_time__update_dialog = 0;
            }
        }

        if (Input.GetKeyDown(KeyCode.A))
        {
            next_dialog(3);
        }
    }

    public void init_state()
    {
        current_row = null;
        next_dialog_id = current_dialog_id = 1;
        stop_next = false;
        is_show_content = false;
        delta_time__update_dialog = 0;

        BdTools.change_state_of_game_object(dialog_canvas_obj, state: false, self: false);
        // dialog_canvas_obj.SetActive(true);

        show_dialog(0);
        // next_dialog();
    }

    public void next_dialog(int jump_to = BdUtils.DEFAULT_INT)
    {
        if (jump_to != BdUtils.DEFAULT_INT)
        {
            next_dialog_id = jump_to;
        }

        if (next_dialog_id == 0)
        {
            // 结束
            if (dbg)
                BdUtils.log("====== end dialog ======");
            exit_dialog_model();
            return;
        }

        // 判断是否应该暂停next_dialog
        if (stop_next)
        {
            if (dbg)
                BdTools.show_message_box(content: "请选择对话选项!", parent_trans: dialog_canvas_trans,
                    position: BdTools.ScreenPositions.center_bottom);
            return;
        }

        if (is_show_content)
        {
            if (dbg)
                BdTools.show_message_box(content: "话还没说完呢...", parent_trans: dialog_canvas_trans,
                    position: BdTools.ScreenPositions.center_bottom);
            return;
        }

        // BdUtils.log("~~~ is_active:", dialog_canvas_obj.activeInHierarchy);
        if (!dialog_canvas_obj.activeInHierarchy || next_dialog_id == 0)
        {
            // 结束
            // BdUtils.log("====== dialog is end! ======");
            return;
        }

        if (current_row == null)
        {
            current_row = TableUtils.get(dialog_dt, pk: next_dialog_id);
            if (current_row == null)
            {
                exit_dialog_model();
                return;
            }
            // BdUtils.assert(current_row, $"current_row不能为空! next_dialog_id: {next_dialog_id}");
        }

        // next_dialog_id = BdUtils.conv_to_int(current_row["next_id"]);

        current_dialog_id = next_dialog_id;
        next_dialog_id = BdUtils.conv_to_int(current_row["next_id"], -1); // `null`等非int值会解析为`-1`

        var id = BdUtils.conv_to_int(current_row["id"]);
        var role = BdUtils.conv_to_string(current_row["role"]);
        var content = BdUtils.conv_to_string(current_row["content"]);
        var position = BdUtils.conv_to_string(current_row["position"]);
        
        var options_string = BdUtils.conv_to_string(current_row["options"]);

        bool is_option;
        // is_option = BdUtils.conv_to_bool(current_row["is_option"]);

        List<DataRow> options = new List<DataRow>();

        if (next_dialog_id == -1)
        {
            if (!BdUtils.is_null(options_string))
            {
                string[] options_array = options_string.Split(new char[]
                {
                    ','
                }, StringSplitOptions.RemoveEmptyEntries);
                
                BdUtils.log($"~~~ options_array: {options_array}");

                foreach (string _option_id in options_array)
                {
                    int option_id = BdUtils.conv_to_int(_option_id);
                    var option_row = TableUtils.get(dialog_dt, pk: option_id);
                    is_option = BdUtils.conv_to_bool(option_row["is_option"]);
                    BdUtils.assert(is_option, "options的id指向的不是option?");
                    options.Add(option_row);
                }
                
                // options = BdUtils.conv_obj_to_list
                // BdUtils.seq_path
                // BdUtils.conv_obj_to_list<int>()
            }

            else 
            {
                // --- 获取options
                // BdUtils.log("--- 获取options");
                is_option = true;
                while (is_option)
                {
                    next_dialog_id = current_dialog_id + 1;
                    current_dialog_id = next_dialog_id;
                    var option_row = TableUtils.get(dialog_dt, pk: next_dialog_id);
                    if (BdUtils.is_null(option_row))
                        break;
                    is_option = BdUtils.conv_to_bool(option_row["is_option"]);
                    if (is_option)
                    {
                        // BdUtils.log("~~~ next_dialog_id:", next_dialog_id, "~~~ is_option:", is_option);
                        options.Add(option_row);
                    }
                    else
                        break;
                }
            }
        }

        if (!BdUtils.is_null(position))
        {
            int dtype;
            if (position == "left" || position == "l")
            {
                dtype = 1;
            }
            else
            {
                dtype = 2;
            }

            if (BdUtils.not_null(options))
            {
                stop_next = true;
                // BdUtils.log("------ stop_next, options.Count:", options.Count);
            }
            
            var _event = BdUtils.conv_to_string(current_row["event"]);
            var e_order = BdUtils.conv_to_int(current_row["e_order"], 1);

            List<int> ls_order = new List<int>
            {
                -1,
                1
            };
            BdUtils.assert(ls_order.Contains(e_order), $"`e_order`取值必须在{ls_order}之中!");

            BdUtils.log("****** e_order:", e_order, "| _event:", _event);
            if (e_order == -1)
            {
                FireEvent(_event, BdUtils.conv_obj_to_json(TableUtils.conv_row_to_dc(current_row)));
            }

            show_dialog(dtype: dtype, content: content, options: options);

            if (e_order == 1)
            {
                FireEvent(_event, BdUtils.conv_obj_to_json(TableUtils.conv_row_to_dc(current_row)));
            }
        }

        // BdUtils.log("--- dialog --- ", "role:", role, ", content:", content, "--- id:", id, ", next_dialog_id:", next_dialog_id);
        current_row = null;
        options = null;
    }

    private GameObject choices_fixed_obj;
    private GameObject choices_dynamic_obj;

    public void show_dialog(int dtype = 1, string content = null, List<DataRow> options = null)
    {
        // string choice_type = "fixed";
        string choice_type = use_dynamic_choice_type ? "dynamic" : "fixed";
        int _dtype_b = dtype == 1 ? 2 : 1;

        int _dtype_a = dtype;
        if (dtype == 0)
            _dtype_a = 1;

        var dialog_a = BdTools.get_game_object_by_path($"dialog_{_dtype_a}", dialog_canvas_obj);
        var dialog_b = BdTools.get_game_object_by_path($"dialog_{_dtype_b}", dialog_canvas_obj);

        BdUtils.assert(dialog_a, "`dialog_a`为空?");
        BdUtils.assert(dialog_b, "`dialog_b`为空?");

        BdTools.change_state_of_game_object(choices_fixed_obj);
        BdTools.change_state_of_game_object(choices_dynamic_obj);

        dialog_b.SetActive(false);

        if (dtype == 0)
        {
            if (dbg)
                BdUtils.log("--- on dtype == 0!", dbg);
            // if(!BdUtils.is_null(dialog_a))
            dialog_a.SetActive(false);
            dialog_b.SetActive(false);
            return;
        }

        var next_button = BdTools.get_game_object_by_path("Chat/Button_Next", dialog_a);
        BdUtils.assert(next_button, "next_button为空?");
        next_button.SetActive(false);
        dialog_a.SetActive(true);

        if (content != null)
        {
            var text_comp = BdTools.get_component_in_obj_self_or_children<TMP_Text>(dialog_a);
            float duration = (float)(content.Length) / 15;
            // Ease easeType = Ease.Linear;
            is_show_content = true;
            DOTween.To(() => text_comp.text = "", x => text_comp.text = x.Replace("\\n", "\n"), content, duration)
                // .SetEase(easeType)
                .OnComplete(
                    () =>
                    {
                        choices_fixed_obj.SetActive(true);
                        choices_dynamic_obj.SetActive(true);
                        next_button.SetActive(true);
                        is_show_content = false;
                    }
                    );

            float t = duration + 0.1f; // [延迟/等待/休眠/timeout]t秒后执行
            DOTween.To(() => t, (x) => t = x, 0, t).OnComplete(
                () =>
                {
                    choices_dynamic_obj.GetComponent<VerticalLayoutGroup>().childForceExpandWidth = true;
                    choices_dynamic_obj.GetComponent<VerticalLayoutGroup>().childForceExpandWidth = false;
                }
                );
        }

        if (!BdUtils.is_null(options))
        {
            for (var i = 0; i < options.Count; i++)
            {
                var option = options[i];
                string content_i = BdUtils.conv_to_string(option["content"]);
                string o_event = BdUtils.conv_to_string(option["event"]);

                string choice_i_path = BdUtils.unity_join(BdTools.get_abs_path_by_obj(dialog_canvas_obj),
                    $"choices_{choice_type}",
                    $"choice_{choice_type}_{i + 1}");

                var choice_i = BdTools.get_game_object_by_path(choice_i_path);
                BdUtils.assert(choice_i, $"choice_i为空? choice_i_path: {choice_i_path}");

                if (use_dynamic_choice_type)
                {
                    var text_comp = BdTools.get_component_in_obj_self_or_children<Text>(choice_i);
                    text_comp.text = content_i;

                    var old_color = text_comp.color;
                    // text_comp.color = new Color(0, 0, 0, 0);
                    text_comp.color = Color.white;
                    text_comp.DOColor(old_color, 2f);

                    float t = 0.5f; // [延迟/等待/休眠/timeout]t秒后执行
                    DOTween.To(() => t, (x) => t = x, 0, t).OnComplete(
                        () =>
                        {
                            choices_dynamic_obj.GetComponent<VerticalLayoutGroup>().childForceExpandWidth = true;
                            choices_dynamic_obj.GetComponent<VerticalLayoutGroup>().childForceExpandWidth = false;
                        }
                        );

                }
                else
                {
                    var text_comp = BdTools.get_component_in_obj_self_or_children<TMP_Text>(choice_i);
                    text_comp.text = content_i;
                }

                int jump_to = BdUtils.conv_to_int(option["next_id"]);

                // --- add call on button click
                var btn_comp = choice_i.transform.GetComponent<Button>();
                BdUtils.assert(btn_comp, "btn_comp不能为null!");
                btn_comp.onClick.RemoveAllListeners();
                btn_comp.onClick.AddListener(() =>
                {
                    // BdUtils.log(" *** OnClickChoiceBtn! content_i:", content_i, "--- o_event:", o_event);
                    FireEvent(o_event, BdUtils.conv_obj_to_json(TableUtils.conv_row_to_dc(option)));

                    stop_next = false;
                    is_show_content = false;
                    delta_time__update_dialog = 0;
                    next_dialog(jump_to: jump_to);
                });

                choice_i.SetActive(true);
            }
        }

        return;
    }

    public void enter_dialog_model()
    {
        dialog_canvas_trans.gameObject.SetActive(true);
        init_state();
        return;
    }

    public void exit_dialog_model()
    {
        init_state();
        dialog_canvas_trans.gameObject.SetActive(false);
        return;
    }

    public void change_dialog_canvas_active_state()
    {
        if (dialog_canvas_trans.gameObject.activeInHierarchy)
        {
            exit_dialog_model();
        }
        else
        {
            enter_dialog_model();
        }
    }

    public void AddEventListener(string envEvent, EventListener listener)
    {
        if (eventListeners.ContainsKey(envEvent))
        {
            BdUtils.assert(!eventListeners.ContainsValue(listener), "AddEventListener对同一个key增加了重复的value!");
            eventListeners[envEvent] += listener;
        }
        else
        {
            eventListeners[envEvent] = listener;
        }
    }

    public void RemoveEventListener(string envEvent, EventListener listener)
    {
        if (eventListeners.ContainsKey(envEvent))
        {
            eventListeners[envEvent] -= listener;
            if (eventListeners[envEvent] == null)
            {
                eventListeners.Remove(envEvent);
            }
        }
    }

    public void FireEvent(string envEvent, string msg)
    {
        if (eventListeners.ContainsKey(envEvent))
        {
            eventListeners[envEvent](msg);
        }
    }
}
